<?php
// +----------------------------------------------------------------------
// | zhanshop-device / Images.php    [ 2024/1/17 下午6:09 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2011~2024 zhangqiquan All rights reserved.
// +----------------------------------------------------------------------
// | Author: zhangqiquan <768617998@qq.com>
// +----------------------------------------------------------------------
declare (strict_types=1);

namespace extend\docker;

use zhanshop\App;
use zhanshop\client\Httpclient;
use zhanshop\ShellCommand;

class Images extends EngineApi
{
    public $enableLog = true;
    public $taskId = 0;
    /**
     * 镜像列表
     * @return array|mixed
     * @throws \Exception
     */
    public function getList()
    {
        $images = $this->request("/images/json");
        $images['body'] = strtolower($images['body'] ?? "");
        $images = json_decode($images['body'], true);
        return $images ?? [];
    }

    /**
     * 删除镜像
     * @param string $id
     * @return array
     * @throws \Exception
     */
    public function delete(string $id)
    {
        $this->request("/images/{$id}?force=1", "DELETE");
        return [];
    }

    /**
     * 搜索镜像
     * @param string $keyword
     * @param $limit
     * @return array|mixed
     * @throws \Exception
     */
    public function search(string $keyword = "PHP", $limit = 100)
    {
        $images = $this->request("/images/search?term=".$keyword.'&limit='.$limit);
        $images = json_decode($images['body'], true);
        return $images ?? [];
    }

    /**
     * 检查镜像详情只能操作本地镜像
     * @param string $name
     * @return array|mixed
     * @throws \Exception
     */
    public function inspect(string $name)
    {
        $image = $this->request("/images/".$name.'/json');
        $image = json_decode($image['body'], true);
        return $image ?? [];
    }

    /**
     * 拉取镜像
     * @param string $name
     * @param callable $callBack
     * @return void
     */
    public function pull(string $name, callable $callBack)
    {
        $this->request("/images/create?fromImage=".$name, "POST", [], $callBack);
    }

    /**
     * 使用dockerfile 构建镜像
     * @param string $dockerFilePath
     * @return void
     */
    public function build(string $dockerFilePath, string $imageName, string $version, mixed $callBack)
    {
        $buildFile = md5(strval(microtime(true))).'.tar';
        ShellCommand::call('cd '.$dockerFilePath.' && tar -cf ../'.$buildFile.' *', function ($msg){});
        /**
         * 参考https://www.cnblogs.com/zcqdream/articles/7127188.html
         *  先另存为 Dockerfile 然后就是打包
         *  tar -cf Dockerfile.tar Dockerfile
         *  curl --unix-socket /var/run/docker.sock -v -XPOST -H "Content-Type: application/tar" --data-binary @Dockerfile.tar http://127.0.0.1/build?t=mynginx:mynginx
         *  然后就是删除
         */
        $isOk = false;
        $curlCmd = 'curl --unix-socket /var/run/docker.sock -v -XPOST -H "Content-Type: application/tar" --data-binary @'.App::runtimePath().'/'.$buildFile.' http://127.0.0.1/build?t='.$imageName.':'.$version;
        App::log()->push($curlCmd, 'DOCKER');
        ShellCommand::call($curlCmd, function ($msg) use (&$isOk){
            if(strpos($msg, 'HTTP/1.1 200 OK') !== false) $isOk = true;
            var_dump($msg);
        });
        $this->setHeader("Content-type", "application/x-tar");
        //$outData = $this->request("/build?t=".$imageName.":".$version, "POST", file_get_contents(App::runtimePath().'/'.$buildFile), $callBack);

        //unlink(App::runtimePath().'/'.$buildFile);
        if($isOk == false){
            App::error()->setError("构建失败");
        }
    }

    /**
     * 删除构建缓存
     * @return void
     */
    public function buildPrune()
    {

    }

    /**
     * 镜像详情
     * @param string $name
     * @return mixed
     * @throws \Exception
     */
    public function detail(string $name)
    {
        $image = $this->request("/images/{$name}/json");
        $image = json_decode($image['body'], true);
        return $image ?? [];
    }

    /**
     * 获取镜像历史记录
     * @param string $name
     * @return mixed
     * @throws \Exception
     */
    public function history(string $name)
    {
        $history = $this->request("/images/{$name}/history");
        $history = json_decode($history['body'], true);
        return $history ?? [];
    }

    /**
     * 导入一个镜像文件
     * @param string $path
     * @return void
     */
    public function load(string $path)
    {
        if(strpos($path, 'http') === 0){
            // 去下载
            $downloadPath = App::runtimePath().'/'.md5($path).'.tar';
            if(file_exists($downloadPath) == false){
                (new Httpclient())->setTimeout(600000)->download($path, $downloadPath);
            }
            $path = $downloadPath;
        }
        $unix = App::env()->get('DOCKER_HOST', '/var/run/docker.sock');
        $command = 'curl --unix-socket '.$unix.' -X POST http://127.0.0.1/images/load -T '.$path;
        $startTime = microtime(true);
        $result = '';
        ShellCommand::call($command, function ($msg) use (&$startTime, &$result){
            $result = $msg;
            $endTime = microtime(true);
            if($this->taskId && ($endTime - $startTime) >= 1){
                $startTime = $endTime;
                App::database()->model("system_tasks")->where(['id' => $this->taskId])->update([
                    'result' => $msg,
                    'status' => 1,
                    'update_time' => time(),
                ]);
            }
        });
        return $result;
    }
}